#ifndef _TIMER_QUEUE_CPP_
#define _TIMER_QUEUE_CPP_

#include "Timer_Queue.h"

template <class TYPE> inline 
int Timer_Queue<TYPE>::expire (void)
{
	if (!this->is_empty ())
		return this->expire (timeGetTime());
	else
		return 0;
}

// Run the <on_timer_out> or <on_timer_cancel> method for all Timers whose values are <= cur_time
template <class TYPE> int
Timer_Queue<TYPE>::expire (unsigned long cur_time)
{
	if (this->is_empty ())
		return 0;

	int number_of_timers_expired = 0;
	Timer_Node<TYPE> *expired = 0;

	if (this->earliest_time () <= cur_time)
	{
		expired = this->remove_first();

		while (expired != 0)
		{
			bool cancel = true;
			++number_of_timers_expired;

			// Check if this is an interval timer.
			if (expired->get_interval () > 0)
			{
				// Make sure that we skip past values that have already "expired".
				do
				expired->set_timer_value (expired->get_timer_value () +
					expired->get_interval ());
				while (expired->get_timer_value () <= cur_time);

				cancel = false;
				// Since this is an interval timer, we need to reschedule it.
				this->reschedule (expired);
			}

			expired->on_timer_out(cur_time);
			if ( cancel )
			{
				expired->on_timer_cancel();
				this->free_node (expired);
			}
		}
	}

	return number_of_timers_expired;
}


template <class TYPE> unsigned long
Timer_Queue<TYPE>::calculate_timeout (unsigned long max_wait_time)
{
	if (this->is_empty ())
		// Nothing on the Timer_Queue, so use whatever the caller gave us.
		return max_wait_time;
	else
	{
		unsigned long cur_time = timeGetTime();

		if (this->earliest_time () > cur_time)
		{
			// The earliest item on the Timer_Queue is still in the
			// future.  Therefore, use the smaller of (1) caller's wait
			// time or (2) the delta time between now and the earliest
			// time on the Timer_Queue.

			this->timeout_ = this->earliest_time () - cur_time;
			if (max_wait_time == 0 || max_wait_time > timeout_)
				return this->timeout_;
			else
				return max_wait_time;
		}
		else
		{
			// The earliest item on the Timer_Queue is now in the past.
			// Therefore, we've got to "poll" the Reactor, i.e., it must
			// just check the descriptors and then dispatch timers, etc.
			this->timeout_ = 0;
			return this->timeout_;
		}
	}
}

template <class TYPE> unsigned long
Timer_Queue<TYPE>::calculate_timeout (unsigned long max_wait_time,
															   unsigned long the_timeout)
{
	if (the_timeout == 0)
		return 0;

	if (this->is_empty ())
	{
		// Nothing on the Timer_Queue, so use whatever the caller gave us.
		if (max_wait_time)
			the_timeout = max_wait_time;
		else
			return 0;
	}
	else
	{
		unsigned long cur_time = timeGetTime();

		if (this->earliest_time () > cur_time)
		{
			// The earliest item on the Timer_Queue is still in the
			// future.  Therefore, use the smaller of (1) caller's wait
			// time or (2) the delta time between now and the earliest
			// time on the Timer_Queue.

			the_timeout = this->earliest_time () - cur_time;
			if (!(max_wait_time == 0 || max_wait_time > the_timeout))
				the_timeout = max_wait_time;
		}
		else
		{
			// The earliest item on the Timer_Queue is now in the past.
			// Therefore, we've got to "poll" the Reactor, i.e., it must
			// just check the descriptors and then dispatch timers, etc.
			the_timeout = 0;
		}
	}
	return the_timeout;
}


template <class TYPE>
Timer_Queue<TYPE>::Timer_Queue (std::list<Timer_Node <TYPE> > *freelist)
															   :delete_free_list_ (freelist == 0)
{
	if (!freelist)
		free_list_ = new std::list< Timer_Node<TYPE> >;
	else
		free_list_ = freelist;
}

template <class TYPE>
Timer_Queue<TYPE>::~Timer_Queue (void)
{
	if (this->delete_free_list_)
		delete this->free_list_;
}

template <class TYPE> 
Timer_Node<TYPE>* Timer_Queue<TYPE>::alloc_node (void)
{
	if ( this->free_list_->empty())
	{
		return new Timer_Node<TYPE>;
	}
	Timer_Node<TYPE>* node = this->free_list_->front();
	this->free_list_->pop_front();
	return node;
}

template <class TYPE> 
void Timer_Queue<TYPE>::free_node ( Timer_Node<TYPE> *node)
{
	if ( this->free_list_->size() <= MAX_TIMER_QUEUE )
	{
		this->free_list_->push_back( node );
	}
	else
		delete node;
}

template <class TYPE> 
long Timer_Queue<TYPE>::schedule (const TYPE &type,
													  const void *arg,
													  unsigned long future_time,
													  unsigned long interval)
{
	// Schedule the timer.
	long result =
		this->schedule_i (type,
		arg,
		future_time,
		interval);

	// Return on failure.
	if (result == -1)
		return result;

	// Return result;
	return result;
}

template <class TYPE> 
void Timer_Queue<TYPE>::return_node ( Timer_Node<TYPE> *node)
{
	this->free_node (node);
}

#endif//_TIMER_QUEUE_CPP_